package tt.dz.biz.service.account;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.springframework.util.CollectionUtils;
import tt.dz.biz.dao.account.AccountingDAO;
import tt.dz.common.BigDecimalUtil;
import tt.dz.common.BusinessException;
import tt.dz.common.DzConstants;
import tt.dz.common.DzConstants.PayType;
import tt.dz.common.DzConstants.balType;
import tt.dz.common.DzConstants.balanceFlag;
import tt.dz.common.DzConstants.borrowOrLoanFlag;
import tt.dz.common.DzConstants.isCostService;
import tt.dz.common.DzConstants.isSelfMerchant;
import tt.dz.common.DzConstants.realTime;
import tt.dz.common.DzConstants.receiveOrPay;
import tt.dz.common.DzConstants.subjectType;
import tt.dz.common.DzConstants.userType;
import tt.dz.common.LogUtil;
import tt.dz.vo.AccountDetailVO;
import tt.dz.vo.AccountingRuleVO;
import tt.dz.vo.MerchAccountDividendVO;
import tt.dz.vo.MerchantSubjectAccVO;
import tt.dz.vo.MerchantVO;
import tt.dz.vo.TranInfoVO;
import tt.dz.vo.TranSubVO;
import tt.dz.vo.UserBaseVO;

public class IndividualToMerchantForImprestPOJO
  extends AccountDividendPOJO
{
  public IndividualToMerchantForImprestPOJO() {}
  
  public IndividualToMerchantForImprestPOJO(TranInfoVO tranInfoVO)
    throws Exception
  {
    super(tranInfoVO);
    init();
  }
  
  public IndividualToMerchantForImprestPOJO init()
    throws Exception
  {
    try
    {
      for (TranSubVO tranSubVO : this.tranSubVOList) {
        if (DzConstants.isSelfMerchant.SELF.value().equals(tranSubVO.getReceiverIsSelf()))
        {
          this.platMerchantCode = tranSubVO.getReceiver();
          break;
        }
      }
    }
    catch (Exception e)
    {
      LogUtil.error("初始化交易记录失败", e);
      throw e;
    }
    return this;
  }
  
  private IndividualToMerchantForImprestPOJO assemblePayerAccountDetail()
    throws Exception
  {
    try
    {
      if ((this.isRealTime) && (DzConstants.userType.PERSONAL_CUSTOMER.value().equals(this.tranInfoVO.getPayerType())))
      {
        AccountDetailVO personlAccountDetail = new AccountDetailVO();
        personlAccountDetail.setAccountingDate(this.accountingDate);
        personlAccountDetail.setSeqNo(queryIndividualDetailSeq());
        personlAccountDetail.setUserId(this.tranInfoVO.getOriginalPayer());
        personlAccountDetail.setMerchantCode(this.platMerchantCode);
        personlAccountDetail.setPayFlag(DzConstants.receiveOrPay.PAY.value());
        personlAccountDetail.setPlatTime(this.platTime);
        personlAccountDetail.setOrderNo(this.tranInfoVO.getOrderNo());
        personlAccountDetail.setTradeNo(this.tranInfoVO.getTradeNo());
        personlAccountDetail.setServiceNo(this.tranInfoVO.getServiceNo());
        personlAccountDetail.setPayTypeCode(this.tranInfoVO.getPayTypeCode());
        personlAccountDetail.setThdPaySeq(this.tranInfoVO.getThdPaySeq());
        personlAccountDetail.setPaymentAmount(this.tranInfoVO.getPaymentAmount());
        this.personalAccountDetailList.add(personlAccountDetail);
      }
    }
    catch (Exception e)
    {
      LogUtil.error("组装个人客户账户详细信息失败", e);
      throw e;
    }
    return this;
  }
  
  private IndividualToMerchantForImprestPOJO assembleReceiveAccountDetail()
    throws Exception
  {
    try
    {
      TranInfoVO tmp = null;
      TranSubVO tranSubVO = null;
      MerchantVO merchantVO = null;
      for (int i = 0; i < this.tranSubVOList.size(); i++)
      {
        tranSubVO = (TranSubVO)this.tranSubVOList.get(i);
        if ((DzConstants.isCostService.IS_COST_SERVICE.value().equals(tranSubVO.getIsCost())) && 
          (DzConstants.isSelfMerchant.SELF.value().equals(tranSubVO.getReceiverIsSelf())))
        {
          TranSubVO costTranSubVO = new TranSubVO();
          merchantVO = this.accountingDAO.queryCostServiceMerchant(tranSubVO.getServiceNo());
          costTranSubVO.setPaymentAmount(tranSubVO.getPaymentAmount());
          costTranSubVO.setReceiver(merchantVO.getMerchantCode());
          costTranSubVO.setReceiverBalType(merchantVO.getBalType());
          costTranSubVO.setServiceNo(tranSubVO.getServiceNo());
          costTranSubVO.setReceiverIsSelf(DzConstants.isSelfMerchant.COPERATION.value());
          costTranSubVO.setPayer(tranSubVO.getReceiver());
          tranSubVO = costTranSubVO;
        }
        this.merchantTranSubList.add(tranSubVO);
        if (DzConstants.isSelfMerchant.COPERATION.value().equals(tranSubVO.getReceiverIsSelf()))
        {
          if (this.totalAmount.containsKey(tranSubVO.getReceiver()))
          {
            tmp = (TranInfoVO)this.totalAmount.get(tranSubVO.getReceiver());
            tmp.setPaymentAmount(BigDecimalUtil.add(tmp.getPaymentAmount(), tranSubVO.getPaymentAmount()));
          }
          else
          {
            tmp = new TranInfoVO();
            tmp.setServiceNo(this.tranInfoVO.getServiceNo());
            tmp.setChannelCode(this.tranInfoVO.getChannelCode());
            tmp.setPaymentAmount(tranSubVO.getPaymentAmount());
            tmp.setReceiver(tranSubVO.getReceiver());
            tmp.setReceiverType(tranSubVO.getReceiverType());
            tmp.setPayStateCode(this.tranInfoVO.getPayStateCode());
            this.totalAmount.put(tmp.getReceiver(), tmp);
          }
          if (DzConstants.realTime.YES.value().equals(tranSubVO.getReceiverBalType())) {
            if (this.needRealTimeTotalAmount.containsKey(tranSubVO.getReceiver()))
            {
              tmp = (TranInfoVO)this.needRealTimeTotalAmount.get(tranSubVO.getReceiver());
              tmp.setPaymentAmount(tmp.getPaymentAmount().add(tranSubVO.getPaymentAmount()));
            }
            else
            {
              tmp = new TranInfoVO();
              tmp.setServiceNo(this.tranInfoVO.getServiceNo());
              tmp.setChannelCode(this.tranInfoVO.getChannelCode());
              tmp.setPaymentAmount(tranSubVO.getPaymentAmount());
              tmp.setReceiver(tranSubVO.getReceiver());
              tmp.setReceiverType(tranSubVO.getReceiverType());
              tmp.setPayStateCode(this.tranInfoVO.getPayStateCode());
              this.needRealTimeTotalAmount.put(tmp.getReceiver(), tmp);
            }
          }
        }
      }
    }
    catch (Exception e)
    {
      LogUtil.error("组装收款人的账户分录信息异常", e);
      throw e;
    }
    return this;
  }
  
  private IndividualToMerchantForImprestPOJO addTotalaccount()
    throws Exception
  {
    try
    {
      TranInfoVO tmp = null;
      MerchAccountDividendVO detail = null;
      MerchantSubjectAccVO mertchSubject = null;
      
      AccountingRuleVO rule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO.getServiceNo(), DzConstants.subjectType.ASSETS.value(), DzConstants.balType.PERIODIC_CLEARING.value());
      AccountingRuleVO relateRule;
      if (!CollectionUtils.isEmpty(this.totalAmount))
      {
        Set<Map.Entry<String, TranInfoVO>> tranInfoSet = this.totalAmount.entrySet();
        
        relateRule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO.getServiceNo(), DzConstants.subjectType.LIABILITIES.value(), DzConstants.balType.PERIODIC_CLEARING.value());
        for (Map.Entry<String, TranInfoVO> entry : tranInfoSet)
        {
          tmp = (TranInfoVO)entry.getValue();
          detail = new MerchAccountDividendVO();
          detail.setTradeNo(this.tranInfoVO.getTradeNo());
          detail.setMerchantCode(tmp.getReceiver());
          detail.setSubjectCode(rule.getSubjectCode());
          detail.setSubSubjectCode(rule.getSubSubjectCode());
          detail.setLoanFlag(rule.getLoanFlag());
          detail.setAmount(tmp.getPaymentAmount());
          
          detail.setMerchantCode1(this.platMerchantCode);
          detail.setAccountingDate(this.accountingDate);
          
          mertchSubject = new MerchantSubjectAccVO();
          mertchSubject.setMerchantCode(detail.getMerchantCode());
          mertchSubject.setSubSubjectCode(detail.getSubSubjectCode());
          if (DzConstants.balanceFlag.REDUCTION.value().equals(rule.getBalanceFlag())) {
            mertchSubject.setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), detail.getAmount()));
          } else {
            mertchSubject.setAcctBal(detail.getAmount());
          }
          this.merchAccountDividendList.add(detail);
          this.merchantSubjectList.add(mertchSubject);
          
          detail = new MerchAccountDividendVO();
          mertchSubject = new MerchantSubjectAccVO();
          detail.setTradeNo(this.tranInfoVO.getTradeNo());
          detail.setMerchantCode(this.platMerchantCode);
          detail.setSubjectCode(relateRule.getSubjectCode());
          detail.setSubSubjectCode(relateRule.getSubSubjectCode());
          detail.setLoanFlag(relateRule.getLoanFlag());
          detail.setAmount(tmp.getPaymentAmount());
          
          detail.setMerchantCode1(tmp.getReceiver());
          detail.setAccountingDate(this.accountingDate);
          mertchSubject = new MerchantSubjectAccVO();
          mertchSubject.setMerchantCode(detail.getMerchantCode());
          mertchSubject.setSubSubjectCode(detail.getSubSubjectCode());
          if (DzConstants.balanceFlag.REDUCTION.value().equals(relateRule.getBalanceFlag())) {
            mertchSubject.setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), detail.getAmount()));
          } else {
            mertchSubject.setAcctBal(detail.getAmount());
          }
          this.merchAccountDividendList.add(detail);
          this.merchantSubjectList.add(mertchSubject);
        }
      }
      if (DzConstants.PayType.IMPREST_PAY.value().equals(this.tranInfoVO.getPayTypeCode()))
      {
        String imprestSubjectCode = this.accountingDAO.queryImprestSubjectByServiceCode(this.tranInfoVO.getServiceNo());
        mertchSubject = new MerchantSubjectAccVO();
        mertchSubject.setMerchantCode(this.platMerchantCode);
        mertchSubject.setSubSubjectCode(imprestSubjectCode);
        mertchSubject.setAcctBal(BigDecimalUtil.sub(DzConstants.BIGDECIMAL_ZERO, this.tranInfoVO.getPaymentAmount()));
        
        detail = new MerchAccountDividendVO();
        detail.setSubSubjectCode(imprestSubjectCode);
        detail.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
        detail.setTradeNo(this.tranInfoVO.getTradeNo());
        detail.setMerchantCode(this.platMerchantCode);
        detail.setAmount(this.tranInfoVO.getPaymentAmount());
        detail.setMerchantCode1(this.tranInfoVO.getPayer());
        detail.setAccountingDate(this.accountingDate);
      }
      else if (DzConstants.PayType.THIRD_REALTIME_PAY.value().equals(this.tranInfoVO.getPayTypeCode()))
      {
        detail = new MerchAccountDividendVO();
        detail.setSubSubjectCode(this.bankSubjectCode);
        detail.setAmount(this.tranInfoVO.getPaymentAmount());
        
        detail.setTradeNo(this.tranInfoVO.getTradeNo());
        detail.setMerchantCode(this.platMerchantCode);
        detail.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
        
        detail.setAmount(this.tranInfoVO.getPaymentAmount());
        detail.setMerchantCode1(this.tranInfoVO.getPayer());
        detail.setAccountingDate(this.accountingDate);
        mertchSubject = new MerchantSubjectAccVO();
        mertchSubject.setMerchantCode(detail.getMerchantCode());
        mertchSubject.setSubSubjectCode(this.bankSubjectCode);
        mertchSubject.setAcctBal(this.tranInfoVO.getPaymentAmount());
      }
      this.merchantSubjectList.add(mertchSubject);
      this.merchAccountDividendList.add(detail);
    }
    catch (Exception e)
    {
      LogUtil.error("处理总账户异常", e);
      throw e;
    }
    return this;
  }
  
  private IndividualToMerchantForImprestPOJO addTranSubToAccountDetailList()
    throws Exception
  {
    try
    {
    	AccountingRuleVO rule = null;
    	AccountingRuleVO  rsRule = null;
      
      MerchAccountDividendVO  detail = null;
      if (!CollectionUtils.isEmpty(this.merchantTranSubList)) {
        for (TranSubVO tmp : this.merchantTranSubList)
        {
          rule = new AccountingRuleVO();
          detail = new MerchAccountDividendVO();
          rule.setSubServiceNo(tmp.getServiceNo());
          rule.setServiceNo(this.tranInfoVO.getServiceNo());
          rsRule = this.accountingDAO.queryRecieverAccountingRule(rule);
          if (null == rsRule) {
            throw new BusinessException("未设置主服务号：" + rule.getServiceNo() + "和子服务号：" + rule.getSubServiceNo() + "对应的损益记账规则。");
          }
          if (DzConstants.isSelfMerchant.SELF.value().equals(tmp.getReceiverIsSelf()))
          {
            setAccountDetail(rsRule, detail, tmp);
            detail.setMerchantCode1(this.tranInfoVO.getPayer());
          }
          else
          {
            setAccountDetail(rsRule, detail, tmp);
            detail.setMerchantCode1(this.platMerchantCode);
          }
          this.merchAccountDividendList.add(detail);
          this.merchantSubjectList.add(setMerchantSubject(detail, rsRule.getBalanceFlag()));
        }
      }
    }
    catch (Exception e)
    {
      AccountingRuleVO rule;
      AccountingRuleVO rsRule;
      MerchAccountDividendVO detail;
      LogUtil.error("交易分录转换成运营商账户分录失败,参数为" + this.merchantTranSubList, e);
      throw e;
    }
    return this;
  }
  
  private void setAccountDetail(AccountingRuleVO rule, MerchAccountDividendVO detail, TranSubVO tmp)
  {
    detail.setAccountingDate(this.accountingDate);
    detail.setMerchantCode(tmp.getReceiver());
    detail.setAmount(tmp.getPaymentAmount());
    detail.setLoanFlag(rule.getLoanFlag());
    detail.setSubjectCode(rule.getSubjectCode());
    detail.setSubSubjectCode(rule.getSubSubjectCode());
    detail.setTradeNo(this.tranInfoVO.getTradeNo());
  }
  
  public void saveAccountDividend()
    throws Exception
  {
    init().assemblePayerAccountDetail().assembleReceiveAccountDetail().addTotalaccount().addTranSubToAccountDetailList();
    if (CollectionUtils.isEmpty(this.merchAccountDividendList)) {
      throw new BusinessException("需要插入的分录列表为空，请检查逻辑");
    }
    this.merchAccountDividendList = mergeMerchAccountDividend(this.merchAccountDividendList);
    int[] mc = this.accountingDAO.insertMerchAccountDividend(this.merchAccountDividendList);
    judgeResult(mc, "插入运营商账户分录，参数为：" + this.merchAccountDividendList);
    int[] pa = this.accountingDAO.insertAccountDetail(this.personalAccountDetailList);
    judgeResult(pa, "插入个人账户明细失败，参数为：" + this.merchAccountDividendList);
    if (DzConstants.userType.ENTERPRISE_CUSTOMER.value().equals(this.tranInfoVO.getOriginalPayerType())) {
      updateEntUserBalance();
    }
  }
  
  private void updateEntUserBalance()
    throws Exception
  {
    UserBaseVO user = new UserBaseVO();
    user.setUserId(this.tranInfoVO.getOriginalPayer());
    user.setBalance(BigDecimalUtil.sub(BigDecimal.valueOf(0L), this.tranInfoVO.getPaymentAmount()));
    this.accountingDAO.updateEntUserBal(user);
  }
}
